package cn.yh.register.order.service.impl;

import cn.yh.register.common.exception.RegisterException;
import cn.yh.register.common.result.ResultCodeEnum;
import cn.yh.register.enums.PaymentTypeEnum;
import cn.yh.register.enums.RefundStatusEnum;
import cn.yh.register.model.order.OrderInfo;
import cn.yh.register.model.order.PaymentInfo;
import cn.yh.register.model.order.RefundInfo;
import cn.yh.register.order.service.OrderService;
import cn.yh.register.order.service.PaymentInfoService;
import cn.yh.register.order.service.RefundInfoService;
import cn.yh.register.order.service.WeixinService;
import cn.yh.register.order.utils.ConstantPropertiesUtils;
import cn.yh.register.order.utils.HttpClient;
import com.alibaba.fastjson.JSONObject;
import com.github.wxpay.sdk.WXPayUtil;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Service
public class WeixinServiceImpl implements WeixinService {

    @Autowired
    private PaymentInfoService paymentInfoService;
    @Autowired
    private OrderService orderService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RefundInfoService refundInfoService;

    /**
     * 对接微信同一下单接口，获取支付二维码
     * @param orderId 订单id
     * @return Map<String, Object>
     */
    @Override
    public Map<String, Object> createNative(Long orderId) {
        Map payMap = (Map) redisTemplate.opsForValue().get(orderId.toString());
        if (null != payMap)
            return payMap;
        // 订单对象
        OrderInfo orderInfo = orderService.getOrderInfo(orderId);
        if (orderInfo == null) {
            throw new RegisterException(ResultCodeEnum.PARAM_ERROR);
        }
        // 保存支付记录
        paymentInfoService.savePaymentInfo(orderInfo, PaymentTypeEnum.WEIXIN.getStatus());
        // 组装参数
        Map<String, String> paramsMap = new HashMap<>();
        paramsMap.put("appid", ConstantPropertiesUtils.APPID);// 公众号appid
        paramsMap.put("nonce_str", WXPayUtil.generateNonceStr());// 随机字符串
        paramsMap.put("mch_id", ConstantPropertiesUtils.PARTNER);// 商户号
        String body = new DateTime(orderInfo.getReserveDate()).toString("yyyy年MM月dd日 ") + "就诊" + orderInfo.getDepname();
        paramsMap.put("body", body);// 订单描述
        paramsMap.put("out_trade_no", orderInfo.getOutTradeNo());// 订单号
        // paramMap.put("total_fee", order.getAmount().multiply(new BigDecimal("100")).longValue()+"");
        paramsMap.put("total_fee", "1");// 订单金额  测试时支付一分钱
        paramsMap.put("spbill_create_ip", "127.0.0.1");// 终端ip
        paramsMap.put("notify_url", "https://2495161sb6.goho.co/api/order/weixinPay/weixinNotify");// 通知地址
        paramsMap.put("trade_type", "NATIVE");// 交易类型  这里使用的是 Native
        paramsMap.put("time_expire", new DateTime().plusMinutes(1).toString("yyyyMMddHHmmss"));// 交易结束时间
        Map<String, String> resultMap = new HashMap<>();
        try {
            // 对接微信的下单接口
            HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
            client.setHttps(true);
            String xmlParam = WXPayUtil.generateSignedXml(paramsMap, ConstantPropertiesUtils.PARTNERKEY);
            client.setXmlParam(xmlParam);
            client.post();
            // 处理返回数据
            String xmlContent = client.getContent();
            // 转map
            resultMap = WXPayUtil.xmlToMap(xmlContent);

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if ("SUCCESS".equals(resultMap.get("result_code")) &&
                "SUCCESS".equals(resultMap.get("return_code"))) {
            Map<String, Object> map = new HashMap<>();
            map.put("orderId", orderId);
            map.put("totalFee", orderInfo.getAmount());
            map.put("resultCode", resultMap.get("result_code"));
            map.put("codeUrl", resultMap.get("code_url"));
            // 将二维码数据放入Redis，设置有效时间
            redisTemplate.opsForValue().set(String.valueOf(orderId), JSONObject.toJSONString(map), 1, TimeUnit.MINUTES);
            return map;
        } else {
            throw new RegisterException(resultMap.get("return_msg") + " " + resultMap.get("err_code_des"), ResultCodeEnum.FAIL.getCode());
        }

    }

    /**
     * 根据订单号去微信第三方查询支付状态
     * @param orderId     订单id
     * @param paymentType 支付类型
     * @return Map<String, String>
     */
    @Override
    public Map<String, String> queryPayStatus(Long orderId, String paymentType) {

        // 订单对象
        OrderInfo orderInfo = orderService.getOrderInfo(orderId);
        if (orderInfo == null) {
            throw new RegisterException(ResultCodeEnum.PARAM_ERROR);
        }
        // 组装参数
        Map<String, String> paramsMap = new HashMap<>();
        paramsMap.put("appid", ConstantPropertiesUtils.APPID);// 公众号appid
        paramsMap.put("nonce_str", WXPayUtil.generateNonceStr());// 随机字符串
        paramsMap.put("mch_id", ConstantPropertiesUtils.PARTNER);// 商户号
        paramsMap.put("out_trade_no", orderInfo.getOutTradeNo());// 订单号
        // 对接微信查询接口
        try {
            HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/orderquery");
            client.setHttps(true);
            client.setXmlParam(WXPayUtil.generateSignedXml(paramsMap, ConstantPropertiesUtils.PARTNERKEY));
            client.post();
            // 返回数据
            String content = client.getContent();
            return WXPayUtil.xmlToMap(content);
        } catch (Exception e) {
            throw new RegisterException("查询结果失败", ResultCodeEnum.FAIL.getCode());
        }

    }

    /**
     * 对接微信退款接口
     * @param orderId 顶单id
     * @return 是否成功
     */
    @Override
    public Boolean refund(Long orderId) {
        // 查询支付记录
        PaymentInfo paymentInfo = paymentInfoService.getPaymentInfo(orderId, PaymentTypeEnum.WEIXIN.getStatus());
        if (paymentInfo == null) {
            throw new RegisterException(ResultCodeEnum.DATA_ERROR);
        }
        // 保存退款记录
        RefundInfo refundInfo = refundInfoService.saveRegundInfo(paymentInfo);
        if (Objects.equals(refundInfo.getRefundStatus() , RefundStatusEnum.REFUND.getStatus())) {
            return true;
        }
        // 组装参数
        Map<String,String> paramMap = new HashMap<>();
        paramMap.put("appid",ConstantPropertiesUtils.APPID);       //公众账号ID
        paramMap.put("mch_id",ConstantPropertiesUtils.PARTNER);   //商户编号
        paramMap.put("nonce_str",WXPayUtil.generateNonceStr());
        paramMap.put("transaction_id",paymentInfo.getTradeNo()); //微信订单号
        paramMap.put("out_trade_no",paymentInfo.getOutTradeNo()); //商户订单编号
        paramMap.put("out_refund_no","tk"+paymentInfo.getOutTradeNo());  //商户退款单号
        paramMap.put("total_fee", "1");
        paramMap.put("refund_fee", "1");
        Map<String, String> resultMap = new HashMap<>();
        try {
            // 对接微信退款接口
            HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/secapi/pay/refund");
            client.setHttps(true);
            client.setCert(true);//需要证书
            client.setCertPassword(ConstantPropertiesUtils.PARTNER);//证书密码默认为商户号
            client.setXmlParam(WXPayUtil.generateSignedXml(paramMap,ConstantPropertiesUtils.PARTNERKEY));
            client.post();
            //获取数据
            String xmlContent = client.getContent();
            resultMap = WXPayUtil.xmlToMap(xmlContent);
        } catch (Exception e) {
            throw new RegisterException("微信退款失败",ResultCodeEnum.FAIL.getCode());
        }
        if ("SUCCESS".equals(resultMap.get("return_code"))
                &&"SUCCESS".equals(resultMap.get("result_code"))) {
            // 退款成功，更新退款记录
            refundInfo.setTradeNo(resultMap.get("refund_id"));
            refundInfo.setRefundStatus(RefundStatusEnum.REFUND.getStatus()); // 2：已退款
            refundInfo.setCallbackContent(JSONObject.toJSONString(resultMap));
            refundInfo.setCallbackTime(new Date());
            refundInfoService.updateById(refundInfo);
            return true;
        }else {
            throw new RegisterException(resultMap.get("return_msg")+ " " +resultMap.get("err_code_des"),
                    ResultCodeEnum.FAIL.getCode());
        }

    }


}
